﻿using LightCAD.MathLib;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.Json.Serialization;

namespace LightCAD.MathLib
{
    public class Line2d : Curve2d
    {

        [JsonInclude]
        public Vector2 Start;
        [JsonInclude]
        public Vector2 End;

        public override bool IsClosed { get => base.IsClosed; }
        public Line2d()
        {
            this.isClosed = false;
            this.Type = Curve2dType.Line2d;
        }

        public Line2d(Vector2 start, Vector2 end) : this()
        {
            Start = start;
            End = end;
        }

        [JsonIgnore]
        public Vector2 Dir => (this.End - this.Start).Normalize();
        [JsonIgnore]
        public double Length => (this.End - this.Start).Length();
        [JsonIgnore]
        public double LengthSq => (this.End - this.Start).LengthSq();

        public override void Copy(Curve2d src)
        {
            var line = src as Line2d;
            this.Start = line.Start.Clone();
            this.End = line.End.Clone();
            this.Name = line.Name;
        }
        public override Curve2d Clone()
        {
            var newObj = new Line2d();
            newObj.Copy(this);
            return newObj;
        }

        public Vector2 Projection(Vector2 p)
        {
            var pointVec = p - this.Start;

            var projectLen = Vector2.Dot(pointVec, this.Dir);
            var projectP = this.Start + (this.Dir * projectLen);
            return projectP;
        }


        public Line2d ApplyMatrix(Matrix3 matrix)
        {
            var sp = matrix.MultiplyPoint(this.Start);
            var ep = matrix.MultiplyPoint(this.End);
            return new Line2d(sp, ep);
        }

        public static bool PointInLine(Line2d line, Vector2 pt, double epsilon = 0.001)
        {
            Vector2 pt1 = line.Start;
            Vector2 pt2 = line.End;
            if (pt.X - Math.Max(pt1.X, pt2.X) > epsilon ||
             Math.Min(pt1.X, pt2.X) - pt.X > epsilon ||
             pt.Y - Math.Max(pt1.Y, pt2.Y) > epsilon ||
             Math.Min(pt1.Y, pt2.Y) - pt.Y > epsilon)
                return false;

            if (Math.Abs(pt2.X - pt1.X) < epsilon)
                return Math.Abs(pt1.X - pt.X) < epsilon || Math.Abs(pt2.X - pt.X) < epsilon;
            if (Math.Abs(pt2.Y - pt1.Y) < epsilon)
                return Math.Abs(pt1.Y - pt.Y) < epsilon || Math.Abs(pt2.Y - pt.Y) < epsilon;

            double x = pt1.X + (pt.Y - pt1.Y) * (pt2.X - pt1.X) / (pt2.Y - pt1.Y);
            double y = pt1.Y + (pt.X - pt1.X) * (pt2.Y - pt1.Y) / (pt2.X - pt1.X);

            return Math.Abs(pt.X - x) < epsilon || Math.Abs(pt.Y - y) < epsilon;
        }
        public static bool PointInLine(Vector2 lineStart, Vector2 lineEnd, Vector2 pt, double epsilon = 0.001)
        {
            Vector2 pt1 = lineStart;
            Vector2 pt2 = lineEnd;

            if (pt.X - Math.Max(pt1.X, pt2.X) > epsilon ||
                Math.Min(pt1.X, pt2.X) - pt.X > epsilon ||
                pt.Y - Math.Max(pt1.Y, pt2.Y) > epsilon ||
                Math.Min(pt1.Y, pt2.Y) - pt.Y > epsilon)
                return false;

            if (Math.Abs(pt2.X - pt1.X) < epsilon)
                return Math.Abs(pt1.X - pt.X) < epsilon || Math.Abs(pt2.X - pt.X) < epsilon;
            if (Math.Abs(pt2.Y - pt1.Y) < epsilon)
                return Math.Abs(pt1.Y - pt.Y) < epsilon || Math.Abs(pt2.Y - pt.Y) < epsilon;

            double x = pt1.X + (pt.Y - pt1.Y) * (pt2.X - pt1.X) / (pt2.Y - pt1.Y);
            double y = pt1.Y + (pt.X - pt1.X) * (pt2.Y - pt1.Y) / (pt2.X - pt1.X);

            return Math.Abs(pt.X - x) < epsilon || Math.Abs(pt.Y - y) < epsilon;
        }
        /// <summary>
        /// 延长线
        /// </summary>
        /// <param name="line"></param>
        /// <param name="lengthen"></param>
        public static Line2d LineLengthen(Line2d line, double lengthen = 250)
        {
            Vector2 pt1 = line.Start;
            Vector2 pt2 = line.End;
            //  Matrix3d.Scale
            return line;

        }
        public static bool LineInLine1(Line2d line, Line2d line2)
        {

            double K = (line.Start.Y - line.End.Y) / (line.Start.X - line.End.X);
            double b = line.Start.Y - line.Start.X * K;
            double K1 = (line2.Start.Y - line2.End.Y) / (line2.Start.X - line2.End.X);
            double b1 = line2.Start.Y - line2.Start.X * K;


            if (MathEx.IsEqual(K, K1) && MathEx.IsEqual(b, b1))
                return true;
            else
                return false;


        }
        public static bool PointInLine11(Line2d line, Vector2 p)
        {



            // 定义线段的起点和终点坐标
            double x1 = line.Start.X;
            double y1 = line.Start.Y;
            double x2 = line.End.X;
            double y2 = line.End.Y;


            double k = (y2 - y1) / (x2 - x1);
            double b = line.Start.Y - line.Start.X * k;
            if (p.Y == (p.X * k + b))
            {
                if ((line.End.Y - p.Y) + (p.Y - line.Start.Y) == (line.End.Y - line.Start.Y) && (line.End.X - p.X) + (p.X - line.Start.X) == (line.End.X - line.Start.X))
                {
                    return true;
                }
                else
                    return false;

            }
            else
            {

                return false;
            }

            // 定义待判断的点的坐标
            double px = p.X;
            double py = p.Y;
            double segmentLength = Math.Sqrt(Math.Pow(x2 - x1, 2) + Math.Pow(y2 - y1, 2));
            // 计算从起点到待判断点的向量和从起点到终点的向量之间的夹角余弦值
            double cosAngle = ((px - x1) * (x2 - x1) + (py - y1) * (y2 - y1)) / (segmentLength * segmentLength);

            // 如果夹角余弦值在0到1之间，则点在线段上
            if (cosAngle >= 0 && cosAngle <= 1)
            {
                return false;
            }

            return true;

        }
        /// <summary>
        /// 点到线的垂足
        /// </summary>
        /// <param name="pt"></param>
        /// <param name="begin"></param>
        /// <param name="end"></param>
        /// <returns></returns>
        public static Vector2 GetFootofperpendicular(Vector2 pt, Vector2 begin, Vector2 end)
        {
            double dx = begin.X - end.X;
            double dy = begin.Y - end.Y;
            if (Math.Abs(dx) < 0.00000001 && Math.Abs(dy) < 0.00000001)
                return begin;
            double u = (pt.X - begin.X) * (begin.X - end.X) +
                (pt.Y - begin.Y) * (begin.Y - end.Y);
            u = u / ((dx * dx) + (dy * dy));


            Vector2 retVal = new Vector2(begin.X + u * dx, begin.Y + u * dy);
            return retVal;
        }
        public static bool ParallelLine(Line2d first, Line2d second, double lengthen = 1)
        {             // 定义第一条线段的起点和终点坐标
            double x1 = first.Start.X;
            double y1 = first.Start.Y;
            double x2 = first.End.X;
            double y2 = first.End.Y;

            // 定义第二条线段的起点和终点坐标
            double x3 = second.Start.X;
            double y3 = second.Start.Y;
            double x4 = second.End.X;
            double y4 = second.End.Y;
            if (Math.Abs(x2 - x1) < 0.0001 && Math.Abs(x4 - x3) < 0.0001)
                return true;
            if (Math.Abs(y2 - y1) < 0.0001 && Math.Abs(y4 - y3) < 0.0001)
                return true;
            // 计算两条线段的斜率
            double slope1 = (y2 - y1) / (x2 - x1);
            double slope2 = (y4 - y3) / (x4 - x3);

            // 判断两条线段是否平行
            if (slope1 == slope2)
            {

                return true;
            }
          
            return false;
        }

        public static bool CrossLine(Line2d first, Line2d second, double lengthen = 1)
        {
         
            // 定义第一条线段的起点和终点坐标
            double x1 = first.Start.X;
            double y1 = first.Start.Y;
            double x2 = first.End.X;
            double y2 = first.End.Y;

            // 定义第二条线段的起点和终点坐标
            double x3 = second.Start.X;
            double x4 = second.End.X;
            double y3 = second.Start.Y;
            double y4 = second.End.Y;
            double slope1 = (y2 - y1) / (x2 - x1);
            double slope2 = (y4 - y3) / (x4 - x3);
            if (Math.Abs(slope1 - slope2) < 1e-10)
            {
                return false;
            }
            Vector2 vector2D = null;
            if (x1 == x2)
            {
                if (y4 == y3)
                {
                    vector2D = new Vector2(x1, y4);
                }
                else
                {
                    vector2D = new Vector2(x1, x1 * slope2 + (y4 - (slope2 * x4)));
                }
            }
            if (y1 == y2)
            {
                if (x3 == x4)
                {
                    vector2D = new Vector2(x4, y1);
                }
                else
                {
                    vector2D = new Vector2((y1 - (y4 - (slope2 * x4))) / slope2, y1);
                }
            }
            if (x3 == x4)
            {
                if (y1 == y2)
                {
                    vector2D = new Vector2(x3, y1);
                }
                else
                {
                    vector2D = new Vector2(x3,x3 * slope1 + (y1 - (slope1 * x1)));
                }
            }
            if (y3 == y4)
            {
                if (x1 == x2)
                {
                    vector2D = new Vector2(x1, y3);
                }
                else
                {
                    vector2D = new Vector2((y3 - (y1 - (slope1 * x1))) / slope1, y3);
                }
            }
            // 计算两条线段的斜率


            // 判断两条线段是否平行

            if (first.Start.Similarity(second.Start) || first.Start.Similarity(second.End) || first.End.Similarity(second.Start) || first.End.Similarity(second.End))
            {
                return true;
            }
            // 计算交点的坐标
            if (vector2D == null)
            {
                double intersectionX = ((x3 * y4 - x4 * y3) * (x2 - x1) - (x1 * y2 - x2 * y1) * (x4 - x3)) /
                                      ((y1 - y2) * (x4 - x3) - (y3 - y4) * (x2 - x1));

                double intersectionY = ((y3 * x4 - y4 * x3) * (y2 - y1) - (y1 * x2 - y2 * x1) * (y4 - y3)) /
                                     ((x1 - x2) * (y4 - y3) - (x3 - x4) * (y2 - y1));
                vector2D = new Vector2(intersectionX, intersectionY);
            }

            if (Line2d.PointInLine(first, vector2D) && Line2d.PointInLine(second, vector2D))
            {
                return true;
                ///"两条线段有交点，交点坐标 intersectionX, intersectionY;
            }
            else
            {
                if (lengthen > 0)
                {
                    if (Vector2.Distance(vector2D, first.Start) <= lengthen || Vector2.Distance(vector2D, first.End) <= lengthen || Vector2.Distance(vector2D, second.Start) <= lengthen || Vector2.Distance(vector2D, second.End) <= lengthen)

                    {
                        return true;
                    }
                }
                return false;
            }
        }
        public static Vector2 GetCrossVector(Line2d first, Line2d second)
        {
            Vector2 cp = new Vector2();
            // 定义第一条线段的起点和终点坐标
            double x1 = first.Start.X;
            double y1 = first.Start.Y;
            double x2 = first.End.X;
            double y2 = first.End.Y;

            // 定义第二条线段的起点和终点坐标
            double x3 = second.Start.X;
            double y3 = second.Start.Y;
            double x4 = second.End.X;
            double y4 = second.End.Y;

            // 计算两条线段的斜率
            double slope1 = (y2 - y1) / (x2 - x1);
            double slope2 = (y4 - y3) / (x4 - x3);

           
            if (x1 == x2)
            {
                if (y4 == y3)
                {
                    return  new Vector2(x1, y4);
                }
                else
                {
                    return new Vector2(x1, x1 * slope2 + (y4 - (slope2 * x4)));
                }
            }
            if (y1 == y2)
            {
                if (x3 == x4)
                {
                    return new Vector2(x4, y1);
                }
                else
                {
                    return new Vector2((y1 - (y4 - (slope2 * x4))) / slope2, y1);
                }
            }
            if (x3 == x4)
            {
                if (y1 == y2)
                {
                    return new Vector2(x3, y1);
                }
                else
                {
                    return new Vector2(x3, x3 * slope1 + (y1 - (slope1 * x1)));
                }
            }
            if (y3 == y4)
            {
                if (x1 == x2)
                {
                    return new Vector2(x1, y3);
                }
                else
                {
                    return new Vector2((y3 - (y1 - (slope1 * x1))) / slope1, y3);
                }
            }
            // 计算交点的坐标
            double intersectionX = ((x3 * y4 - x4 * y3) * (x2 - x1) - (x1 * y2 - x2 * y1) * (x4 - x3)) /
                                  ((y1 - y2) * (x4 - x3) - (y3 - y4) * (x2 - x1));

            double intersectionY = ((y3 * x4 - y4 * x3) * (y2 - y1) - (y1 * x2 - y2 * x1) * (y4 - y3)) /
                                 ((x1 - x2) * (y4 - y3) - (x3 - x4) * (y2 - y1));
            cp.X = intersectionX; cp.Y = intersectionY;
            return cp;

        }



        public static List<Line2d> BreakLineBy2line(Line2d line, Line2d cline1, Line2d cline2)
        {
            List<Line2d> line2Ds = new List<Line2d>();
            Vector2 cp = GetCrossVector(line, cline1);
            Vector2 cp2 = GetCrossVector(line, cline2);
            if (Vector2.Distance(line.Start, cp) < Vector2.Distance(line.Start, cp2))
            {
                Line2d breakline = new Line2d();
                breakline.Start = line.Start;
                breakline.End = cp;
                line2Ds.Add(breakline);
                breakline = new Line2d();
                breakline.Start = cp2;
                breakline.End = line.End;
                line2Ds.Add(breakline);
            }
            else
            {
                Line2d breakline = new Line2d();
                breakline.Start = line.Start;
                breakline.End = cp2;
                line2Ds.Add(breakline);
                breakline = new Line2d();
                breakline.Start = cp;
                breakline.End = line.End;
                line2Ds.Add(breakline);
            }
            return line2Ds;
        }

        public override Curve2d Translate(Vector2 offset)
        {
            this.Start.Add(offset);
            this.End.Add(offset);
            return this;
        }

        public override Curve2d RotateAround(Vector2 basePoint, double angle)
        {
            this.Start.RotateAround(basePoint, angle);
            this.End.RotateAround(basePoint, angle);
            return this;
        }

        public override Curve2d Mirror(Vector2 axisStart, Vector2 axisDir)
        {
            this.Start.Mirror(axisStart, axisDir);
            this.End.Mirror(axisStart, axisDir);
            return this;
        }
        public override Vector2[] GetPoints(int div, double scaleInFuture = 1)
        {
            if (div <= 1)
            {
                return new Vector2[] { Start.Clone(), End.Clone() };
            }
            double len = this.End.DistanceTo(this.Start);
            double divLen = len / div;
            var dir = this.Dir;
            var points = new List<Vector2>()
            {
                this.Start.Clone()
            };
            for (int i = 1; i <= div; i++)
            {
                points.Add(this.Start.Clone().Add(dir.Clone().MultiplyScalar(i * divLen)));
            }
            return points.ToArray();
        }
        public override Curve2d Reverse()
        {
            var temp = this.Start;
            this.Start = this.End;
            this.End = temp;
            return this;
        }

        public override Vector2[] GetPoints() => GetPoints(2);

        public override Curve3d ToCurve3d()
        {
            return new Line3d(this.Start.ToVector3(), this.End.ToVector3());
        }
    }
}
